#include "TinyJsonValue.h"
#include "Array.h"
#include "Object.h"
#include <cstring>
#include <cassert>
namespace tinyjson
{
    TinyJsonValuePtr TinyJsonValue::create_tinyjsonvalue()
    {
        TinyJsonValuePtr ret = std::make_shared<TinyJsonValue>();
        return ret;
    }

    TinyJsonValue::TinyJsonValue()
    {
        m_type = TinyJsonType::TINY_JSON_EMPTY;
    }

    TinyJsonValue::TinyJsonValue(Number number)
    {
        m_values.m_number_value = number;
        m_type = TinyJsonType::TINY_JSON_NUMBER;
    }

    TinyJsonValue::TinyJsonValue(const char *src)
    {
        if (strcmp(src, "null") == 0)
            m_type = TinyJsonType::TINY_JSON_NULL;
        else if (strcmp(src, "true") == 0)
            m_type = TinyJsonType::TINY_JSON_TRUE;
        else if (strcmp(src, "false") == 0)
            m_type = TinyJsonType::TINY_JSON_FALSE;
        else
        {
            m_values.m_string_value = std::make_shared<String>(src);
            m_type = TinyJsonType::TINY_JSON_STRING;
        }
    }

    TinyJsonValue::TinyJsonValue(const String &src)
    {
        if (src == "null")
            m_type = TinyJsonType::TINY_JSON_NULL;
        else if (src == "true")
            m_type = TinyJsonType::TINY_JSON_TRUE;
        else if (src == "false")
            m_type = TinyJsonType::TINY_JSON_FALSE;
        else
        {
            m_values.m_string_value = std::make_shared<String>(src);
            m_type = TinyJsonType::TINY_JSON_STRING;
        }
    }

    TinyJsonValue::TinyJsonValue(const Array &vec)
    {
        m_values.m_array_value = std::make_shared<Array>(vec);
        set_type(TinyJsonType::TINY_JSON_ARRAY);
    }
    TinyJsonValue::TinyJsonValue(const Object &obj)
    {
        m_values.m_object_value = std::make_shared<Object>(obj);
        set_type(TinyJsonType::TINY_JSON_OBJECT);
    }

    void TinyJsonValue::set_type(TinyJsonType type)
    {
        this->m_type = type;
    }

    TinyJsonType TinyJsonValue::get_type() const
    {
        return m_type;
    }

    String TinyJsonValue::get_null() const
    {
        assert(is_null());
        return "null";
    }

    String TinyJsonValue::get_false() const
    {
        assert(is_false());
        return "false";
    }

    String TinyJsonValue::get_true() const
    {
        assert(is_true());
        return "true";
    }

    Number TinyJsonValue::get_number() const
    {
        assert(is_number());
        return m_values.m_number_value;
    }

    String &TinyJsonValue::get_string() const
    {
        assert(is_string());
        return *m_values.m_string_value;
    }

    Array &TinyJsonValue::get_array() const
    {
        assert(is_array());
        return *m_values.m_array_value;
    }

    Object &TinyJsonValue::get_object() const
    {
        assert(is_object());
        return *m_values.m_object_value;
    }

    Boolean TinyJsonValue::is_null() const
    {
        return m_type == TinyJsonType::TINY_JSON_NULL;
    }

    Boolean TinyJsonValue::is_true() const
    {
        return m_type == TinyJsonType::TINY_JSON_TRUE;
    }

    Boolean TinyJsonValue::is_false() const
    {
        return m_type == TinyJsonType::TINY_JSON_FALSE;
    }

    Boolean TinyJsonValue::is_number() const
    {
        return m_type == TinyJsonType::TINY_JSON_NUMBER;
    }

    Boolean TinyJsonValue::is_string() const
    {
        return m_type == TinyJsonType::TINY_JSON_STRING;
    }

    Boolean TinyJsonValue::is_array() const
    {
        return m_type == TinyJsonType::TINY_JSON_ARRAY;
    }

    Boolean TinyJsonValue::is_object() const
    {
        return m_type == TinyJsonType::TINY_JSON_OBJECT;
    }

    void TinyJsonValue::reset()
    {
        if (m_type == TinyJsonType::TINY_JSON_NUMBER)
            m_values.m_number_value = 0;
        else if (m_type == TinyJsonType::TINY_JSON_STRING)
            m_values.m_string_value = 0;
        else if (m_type == TinyJsonType::TINY_JSON_ARRAY)
            m_values.m_array_value = 0;
        else if (m_type == TinyJsonType::TINY_JSON_OBJECT)
            m_values.m_object_value = 0;
        m_type = TinyJsonType::TINY_JSON_EMPTY;
    }

    std::ostream &TinyJsonValue::format_value(std::ostream &out, const TinyJsonValue &value)
    {
        switch (value.get_type())
        {
        case TinyJsonType::TINY_JSON_NULL:
            out << value.get_null();
            break;
        case TinyJsonType::TINY_JSON_TRUE:
            out << value.get_true();
            break;
        case TinyJsonType::TINY_JSON_FALSE:
            out << value.get_false();
            break;
        case TinyJsonType::TINY_JSON_NUMBER:
            out << value.get_number();
            break;
        case TinyJsonType::TINY_JSON_STRING:
            out << value.get_string();
            break;
        case TinyJsonType::TINY_JSON_ARRAY:
            out << value.get_array();
            break;
        case TinyJsonType::TINY_JSON_OBJECT:
            out << value.get_object();
            break;
        default:
            break;
        }
        return out;
    }

    std::ostream &operator<<(std::ostream &out, const TinyJsonValue &value)
    {
        TinyJsonValue::format_value(out, value);
        return out;
    }
}